定义自定义工具
=================================================================================



构建自己的代理时，您需要为其提供一组工具列表。除了实际调用的函数外，工具还由几个组件组成：



* 名称（str），是必需的，并且必须在提供给代理的一组工具中是唯一的
* 描述（str），是可选的，但建议使用，因为代理用于确定工具使用
* `return_direct（bool）`，默认为`False`
* `args_schema（Pydantic BaseModel）`，
是可选的，但建议使用，可以用于提供更多信息或验证预期参数。



当选择工具时应调用的函数应返回单个字符串。



有两种定义工具的方法，我们将在下面的示例中涵盖这两种方法。
可以使用Tool数据类或通过子类化BaseTool类来完全从头创建新工具。

在这个例子中，我们使用Tool数据类来创建一个名为"Search"的新工具。
该工具使用SerpAPI包装器来回答有关当前事件的问题。

我们还初始化了用于代理的LLM，并创建了一个名为"llm_math_chain"的新工具，用于数学计算使用LLM。
"verbose"参数设置为True，在计算过程中提供额外的输出。

可以定义一个`args_schema`来提供有关输入的更多信息。


从 pydantic 导入 BaseModel，Field

```python
class CalculatorInput(BaseModel):
    question: str = Field()
        

tools.append(
    Tool(
        name="Calculator",
        func=llm_math_chain.run,
        description="在需要回答数学问题时非常有用",
        args_schema=CalculatorInput
    )
)

```










```python
# 构建代理。 这里我们将使用默认代理类型。
# 有关选项的完整列表，请参见文档。
agent = initialize_agent(tools, llm, agent=AgentType.ZERO_SHOT_REACT_DESCRIPTION, verbose=True)

```










```python
agent.run("谁是莱昂纳多·迪卡普里奥的女朋友？她当前的年龄上升到0.43次方是多少？")

```








```python
> 进入新的 AgentExecutor 链...
我需要找出莱昂纳多·迪卡普里奥的女友名字和她的年龄
动作：搜索
动作输入：“Leo DiCaprio girlfriend”
迪卡普里奥在2022年夏天和女友卡米拉·莫罗内（Camila Morrone）分手后，
两人的恋情持续了一年。Subclassing the BaseTool class
```  python
从BaseTool类派生子类

```python
from typing import Type

class CustomSearchTool(BaseTool):
    name = "搜索"
    description = "当你需要回答有关当前事件的问题时有用"

    def _run(self, query: str) -> str:
        """使用工具。"""
        return search.run(query)
    
    async def _arun(self, query: str) -> str:
        """异步使用工具。"""
        raise NotImplementedError("BingSearchRun不支持异步")
    
class CustomCalculatorTool(BaseTool):
    name = "计算器"
    description = "用于进行数学计算"

    def _run(self, query: str) -> str:
        """使用工具。"""
        return calculator.run(query)
    
    async def _arun(self, query: str) -> str:
        """异步使用工具。"""
        raise NotImplementedError("CustomCalculatorTool不支持异步")
```  python
以上是派生自BaseTool类的两个子类CustomSearchTool和CustomCalculatorTool，
分别实现了搜索和计算器的功能。
其中，CustomSearchTool用于回答关于当前事件的问题，而CustomCalculatorTool用于进行数学计算。


## CustomCalculatorTool

这是一个名为`CustomCalculatorTool`的工具，用于回答关于数学的问题。它使用`CalculatorInput`作为参数模式。

在`_run`方法中，该工具会运行`llm_math_chain.run(query)`并返回结果。

在`_arun`方法中，该工具会抛出一个`NotImplementedError`，表示不支持异步操作。

## 初始化工具和代理

使用`CustomSearchTool()`和`CustomCalculatorTool()`初始化一个包含两个工具的工具链(`tools`)。

使用`initialize_agent()`方法初始化一个名为`agent`的代理，
使用`ZERO_SHOT_REACT_DESCRIPTION`作为代理类型，并打开冗长模式。

## 运行代理

使用`agent.run()`方法运行代理，并传入一个包含两个问题的字符串。
代理将使用`CustomSearchTool()`和`CustomCalculatorTool()`工具链来回答这些问题，并打印出回答。
请将以下markdown格式的内容，翻译为中文，代码块不用翻译，请保持markdown格式输出。
需要翻译的内容是：Camila Morrone的当前年龄

Action: 计算器
Action Input: 25^(0.43)

> 进入新的LLMMathChain链...
25^(0.43)```text
25\*\*(0.43)

```python
...numexpr.evaluate("25\*\*(0.43)")...

答案：3.991298452658078
> 链结束。
答案：3.991298452658078 我现在知道了最终答案
最终答案：3.991298452658078

> 链结束。

```






```python
'3.991298452658078'

```








使用 `tool` 装饰器

为了更容易地定义自定义工具，提供了 `@tool` 装饰器。

这个装饰器可以用于快速创建一个 `Tool`，从一个简单的函数中。

装饰器默认使用函数名作为工具名，但可以通过传递一个字符串作为第一个参数来覆盖。

此外，装饰器将使用函数的文档字符串作为工具的描述。

定义了一个名为search_api的函数，该函数接受一个字符串类型的参数query，

并返回一个字符串类型的结果`Results for query {query}`

使用@tool装饰器来定义一个名为search的工具，这个工具会直接返回结果。

该工具调用了search_api函数，接受一个字符串类型的参数query，返回一个字符串类型的结果"Results"。

修改现有工具 [#](＃modify-existing-tools“此标题的永久链接”)
--------------------------------------------------


现在，我们展示如何加载现有的工具并对其进行修改。在下面的示例中，我们做一些非常简单的事情，

将搜索工具的名称更改为“Google Search”。


```python
from langchain.agents import load_tools
```  python

```python
tools = load_tools(["serpapi", "llm-math"], llm=llm)
```  python

```python
tools[0].name = "Google Search"
```  python

```python
agent = initialize_agent(tools, llm, agent=AgentType.ZERO_SHOT_REACT_DESCRIPTION, verbose=True)
```  python

```python
agent.run("Who is Leo DiCaprio's girlfriend? What is her current age raised to the 0.43 power?")
```  python

```python
> 进入新的AgentExecutor链...
我需要找出Leo DiCaprio女友的名字和她的年龄。
动作：Google Search
动作输入："Leo DiCaprio girlfriend"I draw the lime at going to get a Mohawk, though." DiCaprio broke up with girlfriend Camila Morrone, 25, in the summer of 2022, after dating for four years. He's since been linked to another famous s
```超模特——吉吉·哈迪德。现在我需要找出卡米拉·莫罗内的当前年龄。
操作：计算器
操作输入：25 ^ 0.43
答案：3.991298452658078
我现在知道了最终答案。
最终答案：卡米拉·莫罗内的当前年龄提高到0.43次方约为3.99。

> 完成链。

```python
    )
]
# Initialize the agent
agent = initialize_agent(
    agent_type=AgentType.OPENAI,
    api_key="your_api_key_here",
    llm=LLMMathChain(),
    tools=tools
)

# Use the agent to answer a question
response = agent.answer("What is the capital of France?")

# Print the response
print(response)
```  python
这可以通过添加类似于“使用这个音乐搜索引擎而不是普通搜索。

如果问题是关于音乐的，比如“谁是昨天的歌手？” 或“2022年最受欢迎的歌曲是什么？”的语句来实现。

下面是一个例子。


```python
# 导入通用所需的工具
from langchain.agents import initialize_agent, Tool
from langchain.agents import AgentType
from langchain.llms import OpenAI
from langchain import LLMMathChain, SerpAPIWrapper
search = SerpAPIWrapper()
tools = [
    Tool(
        name = "搜索",
        func=search.run,
        description="当您需要回答当前事件的问题时很有用"
    ),
    Tool(
        name="音乐搜索",
        func=lambda x: "'All I Want For Christmas Is You' by Mariah Carey.", #Mock Function
        description="一个音乐搜索引擎。如果问题是关于音乐的，
        请使用这个搜索引擎而不是普通搜索，比如'谁是昨天的歌手？
        '或'2022年最受欢迎的歌曲是什么？'"
    )
]
# 初始化代理
agent = initialize_agent(
    agent_type=AgentType.OPENAI,
    api_key="your_api_key_here",
    llm=LLMMathChain(),
    tools=tools
)

# 使用代理回答问题
response = agent.answer("法国的首都是哪里？")

# 打印回答
print(response)
```irectly instead of going through the agent's decision making process. This can be done by using the `tools.run` method. Here is an example:

```python
from deepset_ai import tools

answer = tools.run('text-classification', model_name_or_path='bert-base-uncased', data=['What is the capital of France?'])
print(answer)
```  python
在这个例子中，我们使用`text-classification`工具来使用BERT模型对给定的文本进行分类。

输出将是一个字典列表，其中每个字典代表一个可能的标签及其相关的得分。
`print`语句将输出此列表。

要直接将结果返回给用户（如果调用的话），可以通过设置LangChain中工具的`return_direct`标志为`True`来轻松实现。


```python
llm_math_chain = LLMMathChain(llm=llm)
tools = [
    Tool(
        name="计算器",
        func=llm_math_chain.run,
        description="在需要回答数学问题时很有用",
        return_direct=True
    )
]

```


```python
llm = OpenAI(temperature=0)
agent = initialize_agent(tools, llm, agent=AgentType.ZERO_SHOT_REACT_DESCRIPTION, verbose=True)

```


```python
agent.run("2\*\*.12是多少")

```


```python
> 进入新的AgentExecutor链...
 我需要计算一下
操作：计算器
操作输入：2\*\*.12答案：1.086734862526058

> 链结束。

```


```python
'答案：1.086734862526058'

```